package com.feinno.urcs.group.servlet;

import com.feinno.msrp.MsrpFuture;
import com.feinno.msrp.MsrpFutureListener;
import com.feinno.msrp.MsrpSession;
import com.feinno.msrp.MsrpSessionListenerBase;
import com.feinno.msrp.message.MsrpMessage;
import com.feinno.msrp.message.MsrpResponse;
import com.feinno.msrp.message.SendRequest;
import com.feinno.msrp.message.type.FailureReportType;
import com.feinno.sdp.MediaDescriptionImpl;
import com.feinno.sip.message.SipResponse;
import com.feinno.urcs.content.Sdp;
import com.feinno.urcs.content.UrcsMultipartMimeContent;
import com.feinno.urcs.group.api.GroupMessageLogService;
import com.feinno.urcs.group.log.MessageContentType;
import com.feinno.urcs.group.log.MessageDirection;
import com.feinno.urcs.profile.entity.ClientType;
import com.feinno.urcs.sipservlet.SipSession;
import com.feinno.urcs.sipservlet.msrp.MsrpUtils;
import com.feinno.urcs.types.MobileNo;
import com.feinno.util.CollectionUtils;
import com.feinno.util.Combo2;
import com.feinno.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sdp.SdpException;
import javax.sdp.SessionDescription;
import java.net.InetSocketAddress;
import java.net.URI;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 给外域用户使用, 只是暂存消息, 不负责离线.
 */
public class GroupMemberDialogOutter extends GroupMemberDialog {
	private List<Combo2> list = new ArrayList<Combo2>();
	private static final Logger LOGGER = LoggerFactory.getLogger(GroupMemberDialogOutter.class);

	public GroupMemberDialogOutter(GroupServlet servlet, GroupMessageLogService logService) {
		super(servlet, logService);
	}

	public void addList(Combo2 combo2) {
		list.add(combo2);
	}

	@Override
	public void sendText(MobileNo referBy, String contentType, long groupMessageStorageId, byte[] content) {
		try {
			// TODO: msrp
			LOGGER.info(String.format("sendText GroupMemberDialogOutter GroupId=%s Member=%s remoteMsrpPath=%s ,mediaAlready=%s", getGroupId(), getMemberMobile(), getRemoteMsrpPath(), mediaAlready.get()));
			if (!mediaAlready.get()) {
				//TODO  需要连上之后吧list 发干净
				list.add(new Combo2(contentType, content));
			} else {

				// 获取对端的MSRP真实地址信息
				MsrpFuture future = msrp.sendRequest(remoteMsrpPath, contentType, content);
				future.addListener(new MsrpFutureListener() {
					@Override
					public void sendSuccess(MsrpMessage message) {
						try {
							LOGGER.info(String.format("sendText OK GroupId=%s Member=%s remoteMsrpPath=%s ,content=%s", getGroupId(), getMemberMobile(), getRemoteMsrpPath(), new String((byte[]) content)));
							try {
								logService.textMessageDownstreamLog(String.valueOf(groupMessageStorageId), referBy,
										getMemberMobile().toTelUri().toString(),
										"NF", getGroupUriByGrouupId(), "APP",
										MessageDirection.DOWN,
										MessageContentType.TXT, new String(content),
										DateUtil.getUTCNow(), getRemoteMsrpPath().toString(), 200, "OK");
							} catch (Exception ex) {
								LOGGER.warn("logService error :{}", ex);
							}
							LOGGER.info(String.format("sendText OK GroupId=%s Member=%s " +
									"remoteMsrpPath=%s ,content=%s", getGroupId(), getMemberMobile(), getRemoteMsrpPath(), content));
						} catch (Exception e) {
							LOGGER.error(String.format("  Group Message sendSuccess log error" +
									"To member :%s, error : {}", memberMobile), e);
						}
					}

					@Override
					public void sendFailed(MsrpMessage message, Throwable t) {
						try {
							LOGGER.warn(String.format("sendText msrp error, User=%s Group=%s, remotePath=%s  message=%s", getMemberMobile(), getGroupId(), remoteMsrpPath, message), t);
							MsrpResponse msrpResponse = (MsrpResponse) message;
							list.add(new Combo2(contentType, content));
							try {
								logService.textMessageDownstreamLog(String.valueOf(groupMessageStorageId), referBy,
										memberMobile.toTelUri().toString(),
										"NF", getGroupUriByGrouupId(), "APP", MessageDirection.DOWN,
										MessageContentType.TXT, new String(content), DateUtil.getUTCNow(),
										getRemoteMsrpPath().toString(), msrpResponse.getStatus(), msrpResponse.getDiscription());
							} catch (Exception ex) {
								LOGGER.warn("logService error :{}", ex);
							}
						} catch (Exception e) {
							LOGGER.error(String.format("send Group Message To member :%s, error : {}", memberMobile), e);
						}
						LOGGER.error(String.format("sendText msrp error, User=%s Group=%s, remotePath=%s  message=%s", getMemberMobile(), getGroupId(), remoteMsrpPath, new String((byte[]) content)), t);
					}
				});
			}
		} catch (Exception e) {
			LOGGER.error("  sendText", e);
		}
	}

	/**
	 * 作为应答方 等待对端链接
	 *
	 * @param msrp
	 */
	public void initMsrpSession(MsrpSession msrp) {
		this.msrp = msrp;
		localMsrpPath = msrp.getSessionId();
		msrp.setListener(new MsrpSessionListenerBase() {
			@Override
			public void receivedSendRequest(MsrpSession session, SendRequest send) {
				try {
					LOGGER.info(this.toString() + getMemberMobile());
					mediaAlready.set(true);
					remoteMsrpPath = send.getFromPath().getFirst();
					LOGGER.info(String.format("receivedSendRequest  Start initMsrpSession  GroupId=%s Member=%s remoteMsrpPath=%s send.getContentType() ", getGroupId(), getMemberMobile(), getRemoteMsrpPath(), send.getContentType()));
					LOGGER.info("initMsrpSession" + this);
					if (send.getFailureReport() == FailureReportType.No) {
						MsrpResponse response = send.createSuccessResponse();
						session.sendMessage(response);
					}
					if (send.getContentType() == null) {
						remoteMsrpPath = send.getFromPath().getFirst();
						List<Combo2> list2 = CollectionUtils.cloneList(list);
						for (int i = 0; i < list2.size(); i++) {
							Combo2 commbo2 = list2.get(i);
							MsrpFuture future = msrp.sendRequest(remoteMsrpPath, (String) commbo2.getV1(), (byte[]) commbo2.getV2());
							future.addListener(new MyListener(i) {
								@Override
								public void sendSuccess(MsrpMessage message) {
									try {
										LOGGER.info(String.format("sendText OK List GroupId=%s Member=%s remoteMsrpPath=%s ,content=%s", getGroupId(), getMemberMobile(), getRemoteMsrpPath(), new String((byte[]) commbo2.getV2())));
										list.remove(p);
									} catch (Exception e) {
										LOGGER.error("initMsrpSession  receivedSendRequest", e);
									}
								}

								@Override
								public void sendFailed(MsrpMessage message, Throwable t) {

									LOGGER.error(String.format("sendText Fail List  error, User=%s Group=%s, remotePath=%s  message=%s", getMemberMobile(), getGroupId(), remoteMsrpPath, message), t);
								}
							});
						}
					} else {
						servlet.reciveText(groupId, memberMobile, send.getContentType(), send.getBody(), ClientType.APP, DateUtil.getUTCNow());
					}
					LOGGER.info(String.format("receivedSendRequest  end initMsrpSession  GroupId=%s Member=%s remoteMsrpPath=%s send.getContentType() ", getGroupId(), getMemberMobile(), getRemoteMsrpPath(), send.getContentType()));
				} catch (Exception e) {
					LOGGER.error(String.format("MSRP recive error sessionId=%s  send=%s", session.getSessionId(), send.toString()), e);
				}
			}

			@Override
			public void sessionClosed(MsrpSession session) {
				LOGGER.info(String.format("msrp Serssion closed sessionId=%s", session.getSessionId().toString()));
				localMsrpPath = null;
				closeSipSession();
			}
		});
	}

	public int getGroupId() {
		return groupId;
	}

	public void setGroupId(int groupId) {
		this.groupId = groupId;
	}

	public MobileNo getMemberMobile() {
		return memberMobile;
	}

	@Override
	public void closeSipSession() {
		LOGGER.info(String.format("closeSipSession member=%s group=%s remoteMsrp =%s", getMemberMobile(), getGroupId(), getRemoteMsrpPath()));
		if (getSipSession() != null) getSipSession().bye();
		setSipSession(null);
	}

	@Override
	public void closeMsrp() {
		LOGGER.info(String.format("closeMsrp member=%s group=%s remoteMsrp =%s", getMemberMobile(), getGroupId(), getRemoteMsrpPath()));
		LOGGER.info(String.format("closeMsrp remoteMsrp, this =%s", this));

		if (msrp != null) msrp.close();
	}


	public void setMemberMobile(MobileNo memberMobile) {
		this.memberMobile = memberMobile;
	}

	@Override
	public void hadMoreMessage() {
		LOGGER.info(String.format("hadMoreMessage outDialog  hadMoreMessage GroupID=%s mobileNo=%s listSize =%s", getGroupId(), getMemberMobile(), list.size()));
	}

	@Override
	public void cancel() {
		LOGGER.info(String.format("cancel mobileNo=%s GroupId=%s ( sipSession!=null )= %s ", getMemberMobile(), getGroupId(), getSipSession() != null));
		if (getSipSession() != null) getSipSession().cancel();
	}

	public SipSession getSipSession() {
		return sipSession;
	}

	public void setSipSession(SipSession sipSession) {
		this.sipSession = sipSession;
	}

	public void setRemoteMsrpPath(URI peerMsrpPath) {
		this.remoteMsrpPath = peerMsrpPath;
	}

	public void setLocalMsrpPathBySDP(SessionDescription sdp) throws SdpException, ParseException {
		localMsrpPath = java.net.URI.create(MsrpUtils.getMsrpPath(sdp));
	}

	/**
	 * 处理 对端给应答的 session
	 *
	 * @param response
	 * @throws SdpException
	 * @throws ParseException
	 */
	protected void bindMsrp(SipResponse response) throws SdpException, ParseException {
		LOGGER.info(this.toString() + getMemberMobile());
		UrcsMultipartMimeContent multipartMimeContent = UrcsMultipartMimeContent.newInstance(response.getContentTypeHeader(), response.getRawContent());
		Sdp sdp = multipartMimeContent.getContent(Sdp.class);
		SessionDescription sd = sdp.getSdp();
		boolean isActive = isActive(sd);
		if (!isActive) {
			remoteMsrpPath = java.net.URI.create(MsrpUtils.getMsrpPath(sd));
			LOGGER.info("bindMsrp path:" + remoteMsrpPath + this + "    mobileNo" + getMemberMobile());
			// 如果对端是ACTIVE，只好由我们主动链接，链接成功后返回200，失败则500
			InetSocketAddress remoteAddress = MsrpUtils.getAddressBySdp(sd);
			MsrpFuture msrpFuture = msrp.alive(remoteAddress.getHostString(), remoteAddress.getPort(), remoteMsrpPath);
			msrpFuture.addListener(new MsrpFutureListener() {
				@Override
				public void sendSuccess(MsrpMessage msrpMessage) {
					mediaAlready.set(true);
					LOGGER.info(String.format("msrp active Success  mobile=%s GroupId=%s ,remoteMsrpPath=%s", getMemberMobile(), getGroupId(), remoteMsrpPath));
				}

				@Override
				public void sendFailed(MsrpMessage msrpMessage, Throwable throwable) {
					LOGGER.error(String.format("msrp active Failed  mobile=%s GroupId=%s ,remoteMsrpPath=%s", getMemberMobile(), getGroupId(), remoteMsrpPath), throwable);
				}
			});
		} else {
			LOGGER.info(String.format("msrp active Failed  mobile=%s GroupId=%s ,remoteMsrpPath=%s isActive=%s", getMemberMobile(), getGroupId(), remoteMsrpPath, isActive));
		}
	}

	public static boolean isActive(SessionDescription sdp) throws SdpException, ParseException {
		Iterator itMediaDescriptions = sdp.getMediaDescriptions(true).iterator();
		if (!itMediaDescriptions.hasNext()) {
			return false;
		} else {
			MediaDescriptionImpl md = (MediaDescriptionImpl) itMediaDescriptions.next();
			String setup = md.getAttribute("setup");
			return "active".equalsIgnoreCase(setup);// || "actpass".equalsIgnoreCase(setup);
		}
	}

	static abstract class MyListener implements MsrpFutureListener {
		int p;

		MyListener(int i) {
			p = i;
		}
	}
}
